home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene Storm
/
Scene Storm - Volume 1.iso
/
coding
/
c
/
fp_adpcm
/
playadpcm
/
source
/
playadpcm.c
< prev
Wrap
C/C++ Source or Header
|
1995-08-25
|
13KB
|
547 lines
/* Stand-Alone Player for ADPCM audio samples */
/* Written in 1995 by Christian Buchner. This is Public Domain. */
/* Also look out for xPlay, also available on AmiNet */
/* Note: TAB SIZE = 4 */
/* Includes */
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <libraries/dos.h>
#include <dos/rdargs.h>
#include <utility/tagitem.h>
#include <devices/audio.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <string.h>
#include <hardware/cia.h>
/* Prototypes */
BOOL PlayADPCM(struct MyVars *mv, UBYTE *Filename, ULONG Size, ULONG Filter, ULONG NoFilter, ULONG Quiet);
BOOL OpenAudio(struct MyVars *mv, ULONG Filter, ULONG NoFilter);
void CloseAudio(struct MyVars *mv);
void AbortPlay(struct MyVars *mv);
void WaitPlay(struct MyVars *mv);
extern __asm ULONG DecompressADPCM2( register __a0 UBYTE *Source,
register __d0 ULONG Length,
register __a1 UBYTE *Destination,
register __d1 ULONG JoinCode );
extern __asm ULONG DecompressADPCM3( register __a0 UBYTE *Source,
register __d0 ULONG Length,
register __a1 UBYTE *Destination,
register __d1 ULONG JoinCode );
/* Replay Buffer size */
#define CHIP_SIZE 16384
/* CLI Arguments */
UBYTE Template[]="FILES/M/A,ALL/S,FL=FILTER/S,NFL=NOFILTER/S,QUIET/S";
struct ArgArray
{
UBYTE **aa_Files;
ULONG aa_All;
ULONG aa_Filter;
ULONG aa_NoFilter;
ULONG aa_Quiet;
};
/* Library Bases */
struct DosLibrary *DOSBase;
/* Local Variables */
struct MyVars
{
struct Process *MyProc;
struct MsgPort *LeftReply[2];
struct MsgPort *RightReply[2];
struct IOAudio *LeftAudio[2];
struct IOAudio *RightAudio[2];
BOOL Playing;
UBYTE *ChipBuffer[2];
BOOL BufPlaying[2];
};
/* Access to CIA registers */
struct CIA *ciaa=(struct CIA*)0xbfe001;
/* CLI interface and Pattern Matching */
LONG __saveds main(void)
{
struct MyVars *mv;
UBYTE ProgName[60];
struct RDArgs *RDArgs;
struct ArgArray AA={NULL,FALSE,FALSE,FALSE,FALSE};
char **Files;
struct AnchorPath *AnchorPath;
ULONG ReturnCode=RETURN_FAIL;
if (mv=AllocVec(sizeof(struct MyVars),MEMF_ANY|MEMF_CLEAR))
{
if (DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",37))
{
if (!GetProgramName(ProgName,sizeof(ProgName))) strcpy(ProgName,"PlayADPCM");
if (!(RDArgs=ReadArgs(Template,(LONG *)&AA,0)))
{
PrintFault(IoErr(),ProgName);
}
else
{
if (Files=AA.aa_Files)
{
if (!(AnchorPath=(struct AnchorPath *)AllocVec(sizeof(struct AnchorPath)+256,MEMF_PUBLIC|MEMF_CLEAR)))
{
PrintFault(ERROR_NO_FREE_STORE,ProgName);
}
else
{
ReturnCode=RETURN_OK;
AnchorPath->ap_BreakBits=SIGBREAKF_CTRL_C;
AnchorPath->ap_Strlen=256;
while ((!ReturnCode) && *Files)
{
LONG RetVal;
RetVal=MatchFirst(*Files,AnchorPath);
while(!RetVal)
{
if (AnchorPath->ap_Info.fib_DirEntryType>0L)
{
if ((!(AnchorPath->ap_Flags&APF_DIDDIR))&&AA.aa_All)
{
AnchorPath->ap_Flags|=APF_DODIR;
}
AnchorPath->ap_Flags&=~APF_DIDDIR;
}
else
{
if (PlayADPCM(mv, AnchorPath->ap_Buf, AnchorPath->ap_Info.fib_Size, AA.aa_Filter, AA.aa_NoFilter, AA.aa_Quiet))
{
RetVal=ERROR_BREAK;
break;
}
}
RetVal=MatchNext(AnchorPath);
}
MatchEnd(AnchorPath);
if (RetVal==ERROR_BREAK)
{
PrintFault(RetVal,NULL);
ReturnCode=RETURN_WARN;
}
else
{
if (RetVal!=ERROR_NO_MORE_ENTRIES)
{
PrintFault(RetVal,*Files);
ReturnCode=RETURN_ERROR;
}
}
Files++;
}
FreeVec((APTR)AnchorPath);
}
}
FreeArgs(RDArgs);
}
CloseLibrary((struct Library*)DOSBase);
}
FreeVec(mv);
}
}
/* The primitive sample header */
struct ADPCMHeader
{
UBYTE Identifier[6];
ULONG Frequency;
};
/* The playback routine */
BOOL PlayADPCM(struct MyVars *mv, UBYTE *Filename, ULONG Size, ULONG Filter, ULONG NoFilter, ULONG Quiet)
{
BOOL Break=FALSE;
BPTR File;
struct ADPCMHeader ADPCMHeader;
if (!(File=Open(Filename,MODE_OLDFILE)))
{
PrintFault(IoErr(),Filename);
}
else
{
/* Read in sample header */
if (Read(File,&ADPCMHeader,sizeof(struct ADPCMHeader))==sizeof(struct ADPCMHeader))
{
if (strncmp("ADPCM",ADPCMHeader.Identifier,5))
{
Printf("%s: Not ADPCM format!\n",Filename);
}
else
{
Size-=sizeof(ADPCMHeader);
/* Check if it is a supported ADPCM format */
if (ADPCMHeader.Identifier[5] != '2' && ADPCMHeader.Identifier[5] != '3')
{
Printf("%s: Unsupported ADPCM format!\n",Filename);
}
else
{
ULONG Bits;
/* Retrieve the number of compression bits */
if (ADPCMHeader.Identifier[5] == '2') Bits=2;
if (ADPCMHeader.Identifier[5] == '3') Bits=3;
if (!OpenAudio(mv,Filter,NoFilter))
{
Printf("%s: Can't get audio channels!\n",Filename);
}
else
{
UBYTE *ADPCMBuffer;
ULONG ADPCMSize;
if (Bits==2) ADPCMSize=(CHIP_SIZE+3)/4;
if (Bits==3) ADPCMSize=(CHIP_SIZE+7)/8*3;
if (!(ADPCMBuffer=AllocVec(ADPCMSize, MEMF_ANY|MEMF_CLEAR)))
{
Printf("%s: Out of memory!\n",Filename);
}
else
{
struct Process *MyProc;
ULONG Position=0;
ULONG JoinCode=0;
BOOL ProcActive=TRUE;
ULONG Signals;
UWORD i;
LONG ChipMax, Left, Do, DMALen;
BOOL Aborted=FALSE;
if (!Quiet) Printf("\rPlaying %s",Filename);
MyProc=(struct Process*)FindTask(NULL);
Signal(MyProc,(1L<<mv->LeftReply[0]->mp_SigBit));
Signal(MyProc,(1L<<mv->LeftReply[1]->mp_SigBit));
while(ProcActive)
{
ULONG SigMask = SIGBREAKF_CTRL_C |
(1L<<mv->LeftReply[0]->mp_SigBit) |
(1L<<mv->LeftReply[1]->mp_SigBit) ;
Signals=Wait(SigMask);
if (Signals & SIGBREAKF_CTRL_C)
{
Printf("\n");
AbortPlay(mv);
Break=TRUE;
Aborted=TRUE;
ProcActive=FALSE;
}
for (i=0;ProcActive && i<2;i++)
{
if (Signals & (1L<<mv->LeftReply[i]->mp_SigBit))
{
if (mv->BufPlaying[i])
{
WaitPort(mv->LeftReply[i]); GetMsg(mv->LeftReply[i]);
WaitPort(mv->RightReply[i]); GetMsg(mv->RightReply[i]);
mv->BufPlaying[i]=FALSE;
}
if (Bits==2) ChipMax = (CHIP_SIZE+3)/4;
if (Bits==3) ChipMax = (CHIP_SIZE+7)/8*3;
if (Position>=Size)
{
Position=0;
ProcActive=FALSE;
break;
}
Left = Size-Position;
Do = Left < ChipMax ? Left : ChipMax;
if (Do>0)
{
LONG Got;
if (!Quiet) Printf("\rPlaying %s (%02ld%%)",Filename,100*Position/Size);
if (Got=Read(File, ADPCMBuffer, Do) != Do)
{
if (Got<0) PrintFault(IoErr(),Filename);
else Printf("\r%s: Error, short read!\n",Filename);
Aborted=TRUE;
ProcActive=FALSE;
break;
}
if (Bits==2) JoinCode=DecompressADPCM2(ADPCMBuffer, Do, mv->ChipBuffer[i], JoinCode);
if (Bits==3) JoinCode=DecompressADPCM3(ADPCMBuffer, Do, mv->ChipBuffer[i], JoinCode);
Position+=Do;
if (Bits==2) DMALen = Do*4;
if (Bits==3) DMALen = Do*8/3;
mv->LeftAudio[i]->ioa_Data =
mv->RightAudio[i]->ioa_Data = mv->ChipBuffer[i];
mv->LeftAudio[i]->ioa_Length =
mv->RightAudio[i]->ioa_Length = DMALen;
mv->LeftAudio[i]->ioa_Period =
mv->RightAudio[i]->ioa_Period=(*(struct ExecBase**)(4))->ex_EClockFrequency*5/ADPCMHeader.Frequency;
mv->LeftAudio[i]->ioa_Volume=64;
mv->RightAudio[i]->ioa_Volume=64;
mv->LeftAudio[i]->ioa_Cycles=
mv->RightAudio[i]->ioa_Cycles=1;
mv->LeftAudio[i]->ioa_Request.io_Flags|=ADIOF_PERVOL;
mv->RightAudio[i]->ioa_Request.io_Flags|=ADIOF_PERVOL;
mv->LeftAudio[i]->ioa_Request.io_Command=
mv->RightAudio[i]->ioa_Request.io_Command=CMD_WRITE;
Forbid();
BeginIO(mv->LeftAudio[i]);
BeginIO(mv->RightAudio[i]);
mv->BufPlaying[i]=TRUE;
Permit();
}
}
}
}
WaitPlay(mv);
if ((!Quiet) && (!Aborted)) Printf("\rPlayed %s - OK \n",Filename);
FreeVec(ADPCMBuffer);
}
CloseAudio(mv);
}
}
}
}
Close(File);
}
return(Break);
}
/* Allocate audio channels */
BOOL OpenAudio(struct MyVars *mv, ULONG Filter, ULONG NoFilter)
{
BOOL Success=FALSE;
UWORD i;
UBYTE LeftArray[2]={1,8};
UBYTE RightArray[2]={2,4};
for (i=0;i<2;i++)
{
if (!(mv->LeftReply[i]=CreateMsgPort())) break;
if (!(mv->RightReply[i]=CreateMsgPort())) break;
if (!(mv->LeftAudio[i]=CreateIORequest(mv->LeftReply[i],sizeof(struct IOAudio)))) break;
if (!(mv->RightAudio[i]=CreateIORequest(mv->RightReply[i],sizeof(struct IOAudio)))) break;
if (!(mv->ChipBuffer[i]=AllocVec(CHIP_SIZE,MEMF_CHIP))) break;
}
if (i==2)
{
mv->LeftAudio[0]->ioa_Request.io_Message.mn_Node.ln_Pri=0;
mv->LeftAudio[0]->ioa_Length=sizeof(LeftArray);
mv->LeftAudio[0]->ioa_Data=LeftArray;
mv->LeftAudio[0]->ioa_Request.io_Flags|=ADIOF_NOWAIT;
if (!OpenDevice("audio.device",0L,(struct IORequest *)mv->LeftAudio[0],0))
{
mv->LeftAudio[1]->ioa_Request.io_Device=mv->LeftAudio[0]->ioa_Request.io_Device;
mv->LeftAudio[1]->ioa_Request.io_Unit=mv->LeftAudio[0]->ioa_Request.io_Unit;
mv->LeftAudio[1]->ioa_AllocKey=mv->LeftAudio[0]->ioa_AllocKey;
mv->RightAudio[0]->ioa_Length=sizeof(RightArray);
mv->RightAudio[0]->ioa_Request.io_Message.mn_Node.ln_Pri=0;
mv->RightAudio[0]->ioa_Data=RightArray;
mv->RightAudio[0]->ioa_Request.io_Flags|=ADIOF_NOWAIT;
if (!OpenDevice("audio.device",0L,(struct IORequest *)mv->RightAudio[0],0))
{
mv->RightAudio[1]->ioa_Request.io_Device=mv->RightAudio[0]->ioa_Request.io_Device;
mv->RightAudio[1]->ioa_Request.io_Unit=mv->RightAudio[0]->ioa_Request.io_Unit;
mv->RightAudio[1]->ioa_AllocKey=mv->RightAudio[0]->ioa_AllocKey;
mv->BufPlaying[0]=mv->BufPlaying[1]=FALSE;
if (Filter)
{
ciaa->ciapra &= ~(CIAF_LED);
}
if (NoFilter)
{
ciaa->ciapra |= CIAF_LED;
}
Success=TRUE;
}
}
}
if (!Success)
{
CloseAudio(mv);
}
return(Success);
}
/* Abort playing */
void AbortPlay(struct MyVars *mv)
{
WORD i;
for (i=0;i<2;i++)
{
if (mv->BufPlaying[i])
{
AbortIO(mv->LeftAudio[i]);
AbortIO(mv->RightAudio[i]);
}
}
WaitPlay(mv);
}
/* Wait for audio requests */
void WaitPlay(struct MyVars *mv)
{
WORD i;
for (i=0;i<2;i++)
{
if (mv->BufPlaying[i])
{
WaitPort(mv->LeftReply[i]); GetMsg(mv->LeftReply[i]);
WaitPort(mv->RightReply[i]); GetMsg(mv->RightReply[i]);
mv->BufPlaying[i]=FALSE;
}
}
}
/* Close the audio channels */
void CloseAudio(struct MyVars *mv)
{
WORD i;
for (i=0;i<2;i++)
{
if (mv->BufPlaying[i])
{
AbortIO(mv->LeftAudio[i]);
AbortIO(mv->RightAudio[i]);
WaitPort(mv->LeftReply[i]); GetMsg(mv->LeftReply[i]);
WaitPort(mv->RightReply[i]); GetMsg(mv->RightReply[i]);
mv->BufPlaying[i]=FALSE;
}
}
for (i=1;i>=0;i--)
{
if (mv->ChipBuffer[i])
{
FreeVec(mv->ChipBuffer[i]);
mv->ChipBuffer[i]=NULL;
}
if (mv->RightAudio[i])
{
if (i==0 && mv->RightAudio[i]->ioa_Request.io_Device)
{
CloseDevice(mv->RightAudio[i]);
mv->RightAudio[i]->ioa_Request.io_Device=NULL;
}
DeleteIORequest(mv->RightAudio[i]);
mv->RightAudio[i]=NULL;
}
if (mv->RightReply[i])
{
DeleteMsgPort(mv->RightReply[i]);
mv->RightReply[i]=NULL;
}
if (mv->LeftAudio[i])
{
if (i==0 && mv->LeftAudio[i]->ioa_Request.io_Device)
{
CloseDevice(mv->LeftAudio[i]);
mv->LeftAudio[i]->ioa_Request.io_Device=NULL;
}
DeleteIORequest(mv->LeftAudio[i]);
mv->LeftAudio[i]=NULL;
}
if (mv->LeftReply[i])
{
DeleteMsgPort(mv->LeftReply[i]);
mv->LeftReply[i]=NULL;
}
}
}